package com.wxxymaker.edu.service;

import com.blade.ioc.annotation.Bean;
import com.blade.ioc.annotation.Inject;
import com.wxxymaker.edu.model.entity.Course;
import com.wxxymaker.edu.model.entity.Material;
import com.wxxymaker.edu.model.entity.Task;
import com.wxxymaker.edu.utils.TimeUtils;
import io.github.biezhi.anima.Anima;
import io.github.biezhi.anima.core.AnimaQuery;
import io.github.biezhi.anima.core.Joins;
import io.github.biezhi.anima.enums.OrderBy;
import io.github.biezhi.anima.page.Page;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @AUTHOR soft
 * @DATE 2018/9/16 15:33
 * @DESCRIBE 课程任务基本操作
 */
@Slf4j
@Bean
public class TaskService implements Service<Task> {

    @Inject
    private LearnCourseService learnCourseService;

    @Inject
    private LearnTaskService learnTaskService;

    @Override
    public Task add(Task task) {
        task.setTime(TimeUtils.getTime());
        boolean rollback = Anima.atomic(() -> {
            task.setId(task.save().asInt());
        }).catchException(e -> {
            log.error("任务添加失败! {}", e.getMessage());
        }).isRollback();
        return rollback ? null : task;
    }

    @Override
    public Task delete(Object pk) {
        Task task = byId(pk);
        boolean rollback = Anima.atomic(task::delete).catchException(e -> {
            log.error("任务删除失败! {}", e.getMessage());
        }).isRollback();
        return rollback ? null : task;
    }

    @Override
    public boolean change(Task task) {
        return !Anima.atomic(()->{
            task.updateById(task.getId());
        }).catchException(e -> {
            log.error("任务修改失败! {}", e.getMessage());
        }).isRollback();
    }

    @Override
    public Task byId(Object pk) {
        return this.findOne((Integer) pk, null, false);
    }

    /**
     * 分页查询
     * @param kid  课程id
     * @param uid  用来加入任务学习状态使用
     * @param status 状态
     * @param mater 是否带资源
     * @param page 页码
     * @param size 尺寸
     */
    public Page<Task> page(int kid, Integer uid, Integer status, boolean mater, int page, int size) {
        AnimaQuery<Task> where = Anima.select().from(Task.class).where(Task::getCourseId, kid);

        if (status != null) {
            where.where(Task::getStatus, status);
        }
        if (mater) {
            where.join(Joins.with(Material.class)
                    .as(Task::getMaterial)
                    .on(Task::getMaterialId, Material::getId));
        }
        Page<Task> page1 = where.order(Task::getTime, OrderBy.ASC).page(page, size);
        if (page1.getTotalRows() > 0) {
            for (int i = 0; i < page1.getRows().size(); i++) {
                Task task = page1.getRows().get(i);
                if (uid != null && learnCourseService.isJoin(kid, uid))
                    task.setLearnTask(learnTaskService.byUidAndTaskId(uid, task.getId()));
                task.setIndex_(i + 1);
            }
            return page1;
        }
        return null;
    }

    /**
     * 查询
     * @param tid  任务id
     * @param uid  用户id 存在则加入任务学习状态
     * @param join 是否加入资源
     */
    public Task findOne(int tid, Integer uid, boolean join) {
        AnimaQuery<Task> from = Anima.select().from(Task.class)
                .join(Joins.with(Course.class)
                        .as(Task::getCourse)
                        .on(Task::getCourseId, Course::getId));
        if (join) {
            from.join(Joins.with(Material.class)
                    .as(Task::getMaterial)
                    .on(Task::getMaterialId, Material::getId));
        }
        Task task = from.byId(tid);
        if (uid != null && task != null) {
            task.setIndex_(countIndex(task.getCourseId(), tid));
            task.setLearnTask(learnTaskService.byUidAndTaskId(uid, task.getId()));
        }
        return task;
    }

    /**
     * 获取某课程的前几个任务
     * @param kid 课程id
     * @param limit 限制几个
     */
    public List<Task> findPrev(int kid, int limit) {
        return Anima.select().from(Task.class)
                .where(Task::getCourseId, kid)
                .order(Task::getTime, OrderBy.DESC)
                .page(1, limit).getRows();
    }

    /**
     * 改变任务状态
     * @param tid 任务id
     * @param status 状态
     */
    public boolean setStatus(int tid, Integer status) {
        return Anima.update().from(Task.class)
                .set(Task::getStatus, status)
                .where(Task::getId, tid)
                .execute() > 0;
    }

    /**
     * 判断任务是发布的
     * @param tid 任务id
     */
    public boolean isPublish(int tid) {
        return Anima.select().from(Task.class)
                .where(Task::getId, tid)
                .where(Task::getStatus, 1)
                .count() > 0;
    }

    /**
     * 统计某个课程下的所有任务数
     * @param kid 课程id
     * @param publish 是否发布
     */
    public long count(int kid, boolean publish) {
        AnimaQuery<Task> query = Anima.select().from(Task.class)
                .where(Task::getCourseId, kid);
        if (publish) {
            query.where(Task::getStatus, 1);
        }
        return query.count();
    }

    /**
     * 通过用户id统发布的任务数
     * @param userId 用户id
     */
    public Long count(int userId, Integer status) {
        Long result;
        if (status != null) {
            result = Anima.select().bySQL(Long.class,
                    "select count(*) as taskNum from task where status = ? and" +
                            " course_id in (select id from course where user_id = ?)", status, userId).one();
        } else {
            result = Anima.select().bySQL(Long.class,
                    "select count(*) as taskNum from task where " +
                            "course_id in (select id from course where user_id = ?)", userId).one();
        }
        return result;
    }

    /**
     * 获取当前用户在本课程中的下一个任务
     * @param kid 课程id
     * @param uid 用户id
     * @param publish 是否发布
     */
    public Task getNextTask(int kid, int uid, boolean publish) {
        List<Integer> finishIds = learnTaskService.getFinishIds(kid, uid);

        AnimaQuery<Task> query = Anima.select().from(Task.class)
                .where(Task::getCourseId, kid)
                .order(Task::getId, OrderBy.ASC);
        if (!finishIds.isEmpty()) {
            query.where("id NOT").in(finishIds);
        }
        if (publish) {
            query.where(Task::getStatus, 1);
        }
        Task one = query.one();
        if (one != null) one.setIndex_(countIndex(kid, one.getId())); // 计算课程所在位置 第几节课
        return one;
    }

    /**
     * 计算当前课程在目录中的位置
     * @param kid 课程id
     * @param tid 任务id
     */
    public Integer countIndex(int kid, int tid) {
        return Math.toIntExact(Anima.select().from(Task.class)
                .where(Task::getCourseId, kid)
                .where(Task::getId).lte(tid)
                .count());
    }

    /**
     * 获取该课程下所有任务
     * @param kid 课程id
     */
    public List<Task> findAll(Integer kid) {
        return Anima.select().from(Task.class)
                .where(Task::getCourseId, kid)
                .all();
    }

    public int deleteByKid(int kid) {
        return Anima.delete().from(Task.class)
                .where(Task::getCourseId, kid)
                .execute();
    }
}
